package server;


import java.rmi.RemoteException;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.StringTokenizer;


public class ServerImpl extends java.rmi.server.UnicastRemoteObject implements Server {

    protected SVGWriter                   currentSvgWriter = null;
    protected HashMap<Integer, Processus> listeProcessus   = new HashMap<Integer, Processus>();

    /**
     * Constructeur
     */
    public ServerImpl() throws RemoteException {
        currentSvgWriter = new SVGWriter("observer.svg");
        System.out.println("Serveur démarré");
    }
    
    // ################################################### Fonctions RMI ###################################################
    
    /**
     * Permet d'enregistrer un processus
     * @return Le numéro du processus
     */
    @Override
    public synchronized int register() throws java.rmi.RemoteException {
        int num = listeProcessus.size()+1;
        String nom = "P"+num;
        Processus process = new Processus(num, nom);
        listeProcessus.put(num, process);
        currentSvgWriter.dessinerProcessus(num, nom);
        return num;
    }
    
    /**
     * Permet d'indiquer la fin d'un processus
     */
    @Override
    public synchronized void closeProcessus(int num)
    {
        if(!listeProcessus.containsKey(num)) {
            System.err.println("Erreur closeProcessus() : le processus "+num+" est inconnu");
        }
        else {
            Processus process = listeProcessus.get(num);
            if(process.isClosed()) {
                System.err.println("Erreur closeProcessus() : le processus "+num+" est déjà arrété");
            }
            else {
                process.setClosed(true);
            }
        }
    }
    
    
    /**
     * Fonction permettant de parser les commandes et les exécuter
     */
    @Override
    public synchronized void parseCmd(String cmd) throws java.rmi.RemoteException {
        try {
            
            StringTokenizer st = new StringTokenizer(cmd, ",");
            String action = st.nextToken();

            // SC
            if(action.equals("SC")) {
                if(currentSvgWriter == null) {
                    throw new Exception("Error "+action+" : aucun SVG n'est ouvert");
                }
                int num = Integer.parseInt(st.nextToken());
                int dateDeb = Integer.parseInt(st.nextToken());
                int dateFin = Integer.parseInt(st.nextToken());
                currentSvgWriter.dessinerSC(num, dateDeb, dateFin);
            }
            // AL (Action locale)
            else if(action.equals("AL")) {
                if(currentSvgWriter == null) {
                    throw new Exception("Error "+action+" : aucun SVG n'est ouvert");
                }
                int num = Integer.parseInt(st.nextToken());
                int date = Integer.parseInt(st.nextToken());
                currentSvgWriter.dessinerAL(num, date);
            }
            // REQ | REP | REAL
            else if(action.equals("MSG") || action.equals("REQ") || action.equals("REP") || action.equals("REAL")) {
                if(currentSvgWriter == null) {
                    throw new Exception("Error "+action+" : aucun SVG n'est ouvert");
                }
                int numDep = Integer.parseInt(st.nextToken());
                int numArr = Integer.parseInt(st.nextToken());
                int dateDeb = Integer.parseInt(st.nextToken());
                int dateFin = Integer.parseInt(st.nextToken());
                if(action.equals("MSG")) {
                    currentSvgWriter.dessinerMSG(numDep, numArr, dateDeb, dateFin);
                }
                if(action.equals("REQ")) {
                    currentSvgWriter.dessinerREQ(numDep, numArr, dateDeb, dateFin);
                }
                if(action.equals("REP")) {
                    currentSvgWriter.dessinerREP(numDep, numArr, dateDeb, dateFin);
                }
                if(action.equals("REAL")) {
                    currentSvgWriter.dessinerREAL(numDep, numArr, dateDeb, dateFin);
                }
            }
            // Commande erronée
            else {
                throw new Exception("Commande inconnue");
            }
            
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
    
    // ################################################### GETTERS ###################################################
    /**
     * Renvoi le nombre de processus
     */
    public int getNbProcessus() {
        return listeProcessus.size();
    }
    
    /**
     * Renvoi le nombre de processus non fermé
     */
    public int getNbProcessusUnclosed() {
        int nb = 0;
        for (Entry<Integer, Processus> entry : listeProcessus.entrySet()) {
            if(!entry.getValue().isClosed()) {
                nb++;
            }
        }
        return nb;
    }
    
    
    // ################################################### SETTERS ###################################################
    /**
     * Ferme le fichier SVG
     */
    public void closeSVG()
    {
        currentSvgWriter.close();
        currentSvgWriter = null;
    }
    
    
    // ################################################### MAIN ###################################################
    
    public static void main(String[] args) throws Exception {
        
        try {
            ServerImpl server = new ServerImpl();
            java.rmi.registry.LocateRegistry.createRegistry(1099);
            java.rmi.Naming.bind("rmi://localhost:1099/serverSVG", server);
            
            // On attend au moins un client
            while(server.getNbProcessus() == 0) {
                Thread.sleep(5000);
            }
            
            Thread.sleep(1000);
            
            // Tant qu'il y a des clients actifs (non fermés)
            while(server.getNbProcessusUnclosed() > 0) {
                Thread.sleep(3000);
            }
            
            // On ferme le SVG
            server.closeSVG();
            
            // On arrête le serveur
            System.exit(0);
            
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}
